package com.fattyCorps.common.packet.hero.component.prop;

import cn.hutool.extra.spring.SpringUtil;
import com.fattyCorps.common.enums.battle.prop.EStaticProp;
import com.fattyCorps.common.mgr.GlobalConfig;
import com.fattyCorps.common.packet.hero.component.ABaseHeroComponent;
import com.fattyCorps.common.packet.hero.component.Component;
import com.fattyCorps.common.packet.hero.component.prop.component.BaseProp;
import com.fattyCorps.common.packet.hero.component.prop.component.SkillProp;
import lombok.Data;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

@Data
public class HeroProp extends ABaseHeroComponent {
    private String att; // 攻击
    private String def; // 防御/护甲
    private String maxHp; // 最大hp
    private String speed; // 速度
    private String skillDamagePer; // 技能伤害
    private String precisePer; // 精准
    private String parryPer; // 格挡
    private String criticalPer; // 暴击
    private String criticalDamagePer; // 暴击伤害
    private String armorBreakPer; // 破甲
    private String immunityControlPer; // 免控率
    private String reduceDamagePer; // 减伤率
    private String sacredDamagePer; // 神圣伤害
    private String reduceCriticalPer; // 暴击抵抗
    private String incDamagePer; // 增伤率
    private String incControlPer; // 增控率
    private String combatVal; // 战力

    private Component.Trunk trunk = new Component.Trunk(this);

    private List<String> baseAddProp = new ArrayList<>();
    private List<String> extraMultProp = new ArrayList<>();
    private List<String> extraAddProp = new ArrayList<>();

    @Override
    public void onInit() {
        trunk.addComponent(BaseProp.class);
        trunk.addComponent(SkillProp.class);
        onUpdate();
    }

    private void clearProp() {
        baseAddProp.clear();
        extraMultProp.clear();
        extraAddProp.clear();


        for (EStaticProp value : EStaticProp.values()) {
            baseAddProp.add("0");
            extraMultProp.add("0");
            extraAddProp.add("0");
        }
    }

    @Override
    public void onUpdate() {
        // 清理原有属性
        clearProp();
        // 计算当前等级与星级对应的属性加成与技能
        trunk.onUpdate();
        // 根据属性加成计算最终属性
        calcProp();
        // 修正属性，去掉小数
        correctProps();
        // 计算战力
        calcCombat();
    }

    private void calcCombat() {
        this.combatVal = "";

        GlobalConfig globalConfig = SpringUtil.getBean(GlobalConfig.class);
        double coefAtt = Double.valueOf(globalConfig.getStringValue(GlobalConfig.COMBAT_COEF_ATT));
        double coefCritical = Double.valueOf(globalConfig.getStringValue(GlobalConfig.COMBAT_COEF_CRITICAL));
        double coefDef = Double.valueOf(globalConfig.getStringValue(GlobalConfig.COMBAT_COEF_DEF));
        double coefMaxHp = Double.valueOf(globalConfig.getStringValue(GlobalConfig.COMBAT_COEF_MAX_HP));
        double coefReduceDamage = Double.valueOf(globalConfig.getStringValue(GlobalConfig.COMBAT_COEF_REDUCE_DAMAGE));
        double coefSpeed = Double.valueOf(globalConfig.getStringValue(GlobalConfig.COMBAT_COEF_SPEED));
        double coefSkillDamage = Double.valueOf(globalConfig.getStringValue(GlobalConfig.COMBAT_COEF_SKILL_DAMAGE));
        double coefParry = Double.valueOf(globalConfig.getStringValue(GlobalConfig.COMBAT_COEF_PARRY));
        double coefPrecise = Double.valueOf(globalConfig.getStringValue(GlobalConfig.COMBAT_COEF_PRECISE));
        double coefArmorBreak = Double.valueOf(globalConfig.getStringValue(GlobalConfig.COMBAT_COEF_ARMORBREAK));
        double coefImmunityControl = Double.valueOf(globalConfig.getStringValue(GlobalConfig.COMBAT_COEF_IMMUNITY_CONTROL));
        double coefSacredDamage = Double.valueOf(globalConfig.getStringValue(GlobalConfig.COMBAT_COEF_SACRED_DAMAGE));

        Double dAtt = Double.valueOf(att);
        Double dCriticalPer = Double.valueOf(criticalPer) / 100;
        Double dCriticalDamagePer = Double.valueOf(criticalDamagePer) / 100;
        Double dDef = Double.valueOf(def);
        Double dMaxHp = Double.valueOf(maxHp);
        Double dReduceDamagePer = Double.valueOf(reduceDamagePer) / 100;
        Double dSpeed = Double.valueOf(speed);
        Double dSkillDamagePer = Double.valueOf(skillDamagePer) / 100;
        Double dParryPer = Double.valueOf(parryPer) / 100;
        Double dPrecisePer = Double.valueOf(precisePer) / 100;
        Double dArmorBreakPer = Double.valueOf(armorBreakPer) / 100;
        Double dImmunityControlPer = Double.valueOf(immunityControlPer) / 100;
        Double dSacredDamage = Double.valueOf(sacredDamagePer) / 100;

        if (dCriticalPer > 1) {
            dCriticalPer = 1.0;
        }

        if (dCriticalDamagePer > 1.5) {
            dCriticalDamagePer = 1.5;
        }

        /**
         * 战力=
         * （攻击*攻击战力计算系数）*（1+暴击*（1.5+2*暴击伤害）*暴击战力计算系数 + 防御*防御战力计算系数 +
         * （血量*血量战力计算系数）/（1-减伤）*减伤战力计算系数 +
         * 速度*等级*速度战力计算系数+
         * 技能伤害*攻击*技能伤害战力计算系数 +
         * 格挡*格挡战力计算系数+
         * 精准*精准战力计算系数+
         * 破甲*攻击*破甲战力计算系数+
         * 免控*免控战力计算系数+
         * 神圣伤害*攻击*神圣战力计算系数
         * 备注1：暴击值总值小于等于1，大于1则计为1；
         * 备注2：暴击伤害总值小于等于1.5，大于1.5则计为1.5；
         */
        Double dCombatVal = (dAtt * coefAtt) * (1 + dCriticalPer * (1.5 + 2 * dCriticalDamagePer) * coefCritical + dDef * coefDef) +
                (dMaxHp * coefMaxHp) / (1 - dReduceDamagePer) * coefReduceDamage +
                dSpeed * owner.getLv() * coefSpeed +
                dSkillDamagePer * dAtt * coefSkillDamage +
                dParryPer * coefParry +
                dPrecisePer * coefPrecise +
                dArmorBreakPer * dAtt * coefArmorBreak +
                dImmunityControlPer * coefImmunityControl +
                dSacredDamage * dAtt * coefSacredDamage;

        this.combatVal = Math.round(dCombatVal) + "";
    }

    @Override
    public void onEvent(int e, Object[] objs) {

    }

    public enum ECalcPropType {
        // 增加基础属性
        BaseAdd,
        // 基于基础属性，额外乘以百分比
        ExtraMult,
        // 基于基础属性，额外增加
        ExtraAdd
    }

    public String strAdd(String orgVal, String addVal) {
        BigDecimal addValB = new BigDecimal(addVal);
        BigDecimal orgValB = new BigDecimal(orgVal);
        orgVal = addValB.add(orgValB).toString();

        return orgVal;
    }

    public void incProp(ECalcPropType type, EStaticProp propType, String value) {
        int propIdx = propType.ordinal();

        switch (type) {
            case BaseAdd:
                baseAddProp.set(propIdx, strAdd(baseAddProp.get(propIdx), value));
                break;
            case ExtraAdd:
                extraAddProp.set(propIdx, strAdd(extraAddProp.get(propIdx), value));
                break;
            case ExtraMult:
                extraMultProp.set(propIdx, strAdd(extraMultProp.get(propIdx), value));
                break;
            default:
                break;
        }
    }

    public String getProp(EStaticProp propType) {
        String ret = "0";
        switch (propType) {
            case Att:
                ret = this.att;
                break;
            case Critical:
                ret = this.criticalPer;
                break;
            case ReduceCritical:
                ret = this.reduceCriticalPer;
                break;
            case ImmunityControl:
                ret = this.immunityControlPer;
                break;
            case SacredDamage:
                ret = this.sacredDamagePer;
                break;
            case ReduceDamage:
                ret = this.reduceDamagePer;
                break;
            case SkillDamage:
                ret = this.skillDamagePer;
                break;
            case IncControl:
                ret = this.incControlPer;
                break;
            case ArmorBreak:
                ret = this.armorBreakPer;
                break;
            case IncDamage:
                ret = this.incDamagePer;
                break;
            case Precise:
                ret = this.precisePer;
                break;
            case Speed:
                ret = this.speed;
                break;
            case Parry:
                ret = this.parryPer;
                break;
            case Def:
                ret = this.def;
                break;
            case MaxHp:
                ret = this.maxHp;
                break;
            case CriticalDamage:
                ret = this.criticalDamagePer;
                break;
        }

        if (ret == null) {
            ret = "0";
        }

        return ret;
    }

    public void setProp(EStaticProp propType, String value) {
        switch (propType) {
            case Att:
                att = value;
                break;
            case Critical:
                criticalPer = value;
                break;
            case ReduceCritical:
                reduceCriticalPer = value;
                break;
            case ImmunityControl:
                immunityControlPer = value;
                break;
            case SacredDamage:
                sacredDamagePer = value;
                break;
            case ReduceDamage:
                reduceDamagePer = value;
                break;
            case SkillDamage:
                skillDamagePer = value;
                break;
            case IncControl:
                incControlPer = value;
                break;
            case ArmorBreak:
                armorBreakPer = value;
                break;
            case IncDamage:
                incDamagePer = value;
                break;
            case Precise:
                precisePer = value;
                break;
            case Speed:
                speed = value;
                break;
            case Parry:
                parryPer = value;
                break;
            case Def:
                def = value;
                break;
            case MaxHp:
                maxHp = value;
                break;
            case CriticalDamage:
                criticalDamagePer = value;
                break;
        }
    }

    private void correctProps() {
        correctProp(EStaticProp.Att);
        correctProp(EStaticProp.Def);
        correctProp(EStaticProp.MaxHp);
    }

    // 修正，去掉小数
    private void correctProp(EStaticProp propType) {
        String prop = getProp(propType);
        BigDecimal b = new BigDecimal(prop);
        setProp(propType, "" + b.longValue());
    }

    private void calcProp() {
        // 最终属性=基础属性+基础属性*额外属性百分比加成+额外属性固定加成
        for (EStaticProp value : EStaticProp.values()) {
            int index = value.ordinal();
            String basePropVal = baseAddProp.get(index);
            String extraMultPropVal = extraMultProp.get(index);
            String extraAddPropVal = extraAddProp.get(index);

            BigDecimal basePropValB = new BigDecimal(basePropVal);
            BigDecimal extraMultPropValB = new BigDecimal(extraMultPropVal);
            BigDecimal extraAddPropValB = new BigDecimal(extraAddPropVal);

            String finalVal = basePropValB.add(basePropValB.multiply(extraMultPropValB)).add(extraAddPropValB).toString();
            setProp(value, finalVal);
        }
    }

    public long getCombatVal() {
        if (StringUtils.isEmpty(this.combatVal)) {
            return 0;
        }

        return Long.valueOf(this.combatVal);
    }
}
